1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: Mac\040OS\040Test\040Searcher.c,v $
20 Revision 1.23 2007/07/27 19:30:40 cheshire
21 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
22 to properly reflect tri-state nature of the possible responses
24 Revision 1.22 2006/08/14 23:24:29 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
27 Revision 1.21 2004/12/16 20:49:34 cheshire
28 <rdar://problem/3324626> Cache memory management improvements
30 Revision 1.20 2004/10/19 21:33:18 cheshire
31 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
32 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
33 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
35 Revision 1.19 2004/09/17 01:08:50 cheshire
36 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
37 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
38 declared in that file are ONLY appropriate to single-address-space embedded applications.
39 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
41 Revision 1.18 2004/09/16 21:59:16 cheshire
42 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
44 Revision 1.17 2004/06/10 04:37:27 cheshire
45 Add new parameter in mDNS_GetDomains()
47 Revision 1.16 2004/03/12 21:30:25 cheshire
48 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
49 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
51 Revision 1.15 2004/01/24 23:55:15 cheshire
52 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
54 Revision 1.14 2003/11/14 21:27:09 cheshire
55 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
56 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
58 Revision 1.13 2003/08/14 02:19:54 cheshire
59 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
61 Revision 1.12 2003/08/12 19:56:24 cheshire
66 #include <stdio.h> // For printf()
67 #include <Events.h> // For WaitNextEvent()
68 #include <SIOUX.h> // For SIOUXHandleOneEvent()
70 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
71 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
75 OTLIFO serviceinfolist
;
76 Boolean headerPrinted
;
80 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
82 // These don't have to be globals, but their memory does need to remain valid for as
83 // long as the search is going on. They are declared as globals here for simplicity.
84 #define RR_CACHE_SIZE 1000
85 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
86 static mDNS mDNSStorage
;
87 static mDNS_PlatformSupport PlatformSupportStorage
;
88 static SearcherServices services
;
89 static DNSQuestion browsequestion
, domainquestion
;
91 // PrintServiceInfo prints the service information to standard out
92 // A real application might want to do something else with the information
93 static void PrintServiceInfo(SearcherServices
*services
)
95 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
99 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
100 ServiceInfo
*s
= &ls
->i
;
102 if (!services
->headerPrinted
)
104 printf("%-55s Type Domain IP Address Port Info\n", "Name");
105 services
->headerPrinted
= true;
110 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
111 ConvertDomainNameToCString(&s
->name
, c_dom
);
112 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
113 else printf("%-55s no longer available for browsing\n", c_dom
);
118 domainname type
, domain
;
119 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
120 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
121 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
122 ConvertDomainNameToCString(&type
, c_type
);
123 ConvertDomainNameToCString(&domain
, c_dom
);
124 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
126 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
127 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
128 else printf("Removed\n");
136 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
137 // enqueues a record for PrintServiceInfo() to print.
138 // Note, a browsing application would *not* normally need to get all this information --
139 // all it needs is the name, to display to the user.
140 // Finding out the address, port, and txtinfo should be deferred to the time that the user
141 // actually needs to contact the service to use it.
142 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
144 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
145 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
146 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
148 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
149 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
154 // When a new named instance of a service is found, FoundInstance() is called.
155 // In this sample code we turn around and immediately issue a query to resolve that service name to
156 // find its address, port, and txtinfo, but a normal browing application would just display the name.
157 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
159 #pragma unused (question)
160 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
161 linkedServiceInfo
*info
;
163 debugf("FoundInstance %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
165 if (answer
->rrtype
!= kDNSType_PTR
) return;
166 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
168 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
169 if (!info
) { services
->lostRecords
= true; return; }
171 info
->i
.name
= answer
->rdata
->u
.name
;
172 info
->i
.InterfaceID
= answer
->InterfaceID
;
173 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
174 info
->i
.ip
.ip
.v4
= zerov4Addr
;
175 info
->i
.port
= zeroIPPort
;
176 info
->add
= AddRecord
;
177 info
->dom
= mDNSfalse
;
179 if (!AddRecord
) // If TTL == 0 we're deleting a service,
180 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
181 else // else we're adding a new service
183 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
184 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
185 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
189 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
192 #pragma unused (question)
193 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
194 linkedServiceInfo
*info
;
196 debugf("FoundDomain %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
198 if (answer
->rrtype
!= kDNSType_PTR
) return;
199 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
201 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
202 if (!info
) { services
->lostRecords
= true; return; }
204 info
->i
.name
= answer
->rdata
->u
.name
;
205 info
->i
.InterfaceID
= answer
->InterfaceID
;
206 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
207 info
->i
.ip
.ip
.v4
= zerov4Addr
;
208 info
->i
.port
= zeroIPPort
;
209 info
->add
= AddRecord
;
210 info
->dom
= mDNStrue
;
212 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
215 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
216 static Boolean
YieldSomeTime(UInt32 milliseconds
)
218 extern Boolean SIOUXQuitting
;
220 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
221 SIOUXHandleOneEvent(&e
);
222 return(SIOUXQuitting
);
228 Boolean DoneSetup
= false;
231 SIOUXSettings
.asktosaveonclose
= false;
232 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
233 SIOUXSettings
.rows
= 40;
234 SIOUXSettings
.columns
= 132;
236 printf("Multicast DNS Searcher\n\n");
237 printf("This software reports errors using MacsBug breaks,\n");
238 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
239 printf("******************************************************************************\n");
241 err
= InitOpenTransport();
242 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
244 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
245 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
246 if (err
) return(err
);
248 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
249 tempmem
= OTAllocMem(0x10000);
250 if (tempmem
) OTFreeMem(tempmem
);
251 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
253 services
.serviceinfolist
.fHead
= NULL
;
254 services
.headerPrinted
= false;
255 services
.lostRecords
= false;
257 while (!YieldSomeTime(35))
259 #if MDNS_ONLYSYSTEMTASK
260 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
261 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
262 extern void mDNSPlatformIdle(mDNS
*const m
);
263 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
265 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
267 domainname srvtype
, srvdom
;
269 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
270 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
271 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
272 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, &services
);
274 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
278 if (services
.serviceinfolist
.fHead
)
279 PrintServiceInfo(&services
);
281 if (services
.lostRecords
)
283 services
.lostRecords
= false;
284 printf("**** Warning: Out of memory: Records have been missed.\n");
288 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
289 mDNS_Close(&mDNSStorage
);